#ifndef DW_SYSTEM_SLOT_HPP
# define DW_SYSTEM_SLOT_HPP

#	ifdef DW_TRACE_INCLUDES
#		pragma message("-- include dw/system/slot.hpp")
#	endif // DW_TRACE_INCLUDES

#	define SLOT_CTORS(Class, MethodPtr)																						\
		Slot(Class* object, MethodPtr method) : _object(object), _method(method) {}

namespace dw
{
	namespace	system
	{	
		/// abstract class for 4 arguments slots
		template <typename Arg1Type = void, typename Arg2Type = void, typename Arg3Type = void, typename Arg4Type = void>
		class _Slot
		{
		public:

			virtual void call(Arg1Type, Arg2Type, Arg3Type, Arg4Type) const = 0;

		};
		
		/// abstract class for 3 arguments slots
		template <typename Arg1Type, typename Arg2Type, typename Arg3Type>
		class _Slot<Arg1Type, Arg2Type, Arg3Type>
		{
		public:

			virtual void call(Arg1Type, Arg2Type, Arg3Type) const = 0;

		};
		
		/// abstract class for 2 arguments slots
		template <typename Arg1Type , typename Arg2Type>
		class _Slot<Arg1Type, Arg2Type>
		{
		public:

			virtual void call(Arg1Type, Arg2Type) const = 0;

		};
		
		/// abstract class for 1 argument slots
		template <typename Arg1Type>
		class _Slot<Arg1Type>
		{
		public:

			virtual void call(Arg1Type) const = 0;

		};
		
		/// abstract class for 0 argument slots
		template <>
		class _Slot<>
		{
		public:

			virtual void call() const = 0;

		};
		
		/// class for 4 arguments slots for Class
		template <class Class, typename Arg1Type = void, typename Arg2Type = void, typename Arg3Type = void, typename Arg4Type = void>
		class Slot : public _Slot<Arg1Type, Arg2Type, Arg3Type, Arg4Type>
		{
		public:
			
			typedef void (Class::*MethodPtr)(Arg1Type, Arg2Type, Arg3Type, Arg4Type);
			
			SLOT_CTORS(Class, MethodPtr)
			
			void call(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3, Arg4Type arg4) const { return (_object->*_method)(arg1, arg2, arg3, arg4); }

		private:

			Class*		_object;
			
			MethodPtr _method;

		};
		
		/// class for 3 arguments slots for Class
		template <class Class, typename Arg1Type, typename Arg2Type, typename Arg3Type>
		class Slot<Class, Arg1Type, Arg2Type, Arg3Type> : public _Slot<Arg1Type, Arg2Type, Arg3Type>
		{
		public:

			typedef void (Class::*MethodPtr)(Arg1Type, Arg2Type, Arg3Type);
			
			SLOT_CTORS(Class, MethodPtr)
			
			void call(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) const { return (_object->*_method)(arg1, arg2, arg3); }

		private:

			Class*		_object;
			
			MethodPtr _method;

		};
		
		/// class for 2 arguments slots for Class
		template <class Class, typename Arg1Type, typename Arg2Type>
		class Slot<Class, Arg1Type, Arg2Type> : public _Slot<Arg1Type, Arg2Type>
		{
		public:

			typedef void (Class::*MethodPtr)(Arg1Type, Arg2Type);
			
			SLOT_CTORS(Class, MethodPtr)
			
			void call(Arg1Type arg1, Arg2Type arg2) const { return (_object->*_method)(arg1, arg2); }

		private:
			
			Class*		_object;
			
			MethodPtr _method;

		};
		
		/// class for 1 argument slots for Class
		template <class Class, typename Arg1Type>
		class Slot<Class, Arg1Type> : public _Slot<Arg1Type>
		{
		public:

			typedef void (Class::*MethodPtr)(Arg1Type);
			
			SLOT_CTORS(Class, MethodPtr)
			
			void call(Arg1Type arg1) const { return (_object->*_method)(arg1); }

		private:

			Class*		_object;
			
			MethodPtr _method;

		};
		
		//! class for 0 argument slots for Class
		template <class Class>
		class Slot<Class> : public _Slot<>
		{
		public:
			
			typedef void (Class::*MethodPtr)();
			
			SLOT_CTORS(Class, MethodPtr)
			
			void call() const { return (_object->*_method)(); }
		
		private:
			
			Class*		_object;
			
			MethodPtr _method;

		};
		
	} // namespace system
} // namespace dw

#endif // DW_SYSTEM_SLOT_HPP

